package com.mandao.concurrency.interviewset.pooldemo;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* Description:
    java实现阻塞队列
* @author woniu
*/
public class BlockQueue<T> {

    private int size;
    private Object[] queue;

    /**
        ReentrantLock implements Lock, java.io.Serializable
        ReentrantLock 有公平锁和非公平锁
     */
    private Lock lock = new ReentrantLock();
    /**
     * Condition 是绑定在lock上的
     */
    private Condition full = lock.newCondition();
    private Condition empty = lock.newCondition();

    private int index;
    private int removeIndex;
    private int currLen;

    /**
     * 构造函数 初始化队列10
     */
    public BlockQueue() {
        this(10);
    }

    public BlockQueue(int size) {
        this.index = 0;
        this.removeIndex = 0;
        this.currLen = 0;
        this.size = size;
        queue = new Object[size];
    }

    /**
     * @param element
     * @throws InterruptedException  中断异常
     */
    public void push(T element) throws InterruptedException {
        lock.lock();
        try {
            while (currLen == size) {
                System.out.println("队列满。。。");
                full.await();
            }
            queue[index] = element;
            if (++index == size) {
                index = 0;
            }
            currLen++;
            empty.signal();
        } finally {
            lock.unlock();
        }
    }

    private T pop() throws InterruptedException {
        lock.lock();
        try {
            while (currLen == 0) {
                System.out.println("队列空。。。");
                empty.await();
            }
            Object obj = queue[removeIndex];
            if (++removeIndex == size) {
                removeIndex = 0;
            }
            currLen--;
            full.signal();
            return (T) obj;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        BlockQueue<Integer> blockQueue = new BlockQueue<Integer>(3);
        blockQueue.push(1);
        System.out.println(blockQueue.pop());
        blockQueue.push(2);
        System.out.println(blockQueue.pop());
        blockQueue.push(3);
        System.out.println(blockQueue.pop());

        blockQueue.push(5);
        blockQueue.push(5);
        System.out.println(blockQueue.pop());
    }

}
